package main

import (
	"embed"
	"fmt"
	"os"

	"io/fs"
	"log"
	"net/http"
	"net/url"

	"sync"

	"gitee.com/mad-wud/lin"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
)

//go:embed 网页端开发环境/dist/*
var 桌面端代码 embed.FS

var ws链接设置 = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
	ReadBufferSize:  1024, //读取最大长度
	WriteBufferSize: 2048, //发送最大长度
}

func 启动后端服务器() {
	服务端 := gin.Default()
	静态文件, _ := fs.Sub(桌面端代码, "网页端开发环境/dist/assets")
	首页文件, _ := fs.Sub(桌面端代码, "网页端开发环境/dist")
	服务端.StaticFS("/assets", http.FS(静态文件))
	服务端.Handle("GET", "/", func(ctx *gin.Context) {
		主html, err := 首页文件.Open("index.html")
		if err != nil {
			log.Fatal(err)
		}
		defer 主html.Close()
		文件, err := 主html.Stat()
		if err != nil {
			log.Fatal(err)
		}
		ctx.DataFromReader(http.StatusOK, 文件.Size(), "text/html", 主html, nil)
	})
	服务端.NoRoute(func(ctx *gin.Context) {
		请求路径 := ctx.Request.URL.Path
		if 全_文本.P判断前缀(请求路径, "/assets/") {
			主html, err := 首页文件.Open("index.html")
			if err != nil {
				log.Fatal(err)
			}
			defer 主html.Close()
			文件, err := 主html.Stat()
			if err != nil {
				log.Fatal(err)
			}
			ctx.DataFromReader(http.StatusOK, 文件.Size(), "text/html", 主html, nil)
		} else {
			ctx.Status(http.StatusNotFound)
		}

	})

	// 数据服务入口
	服务端.POST("/linask", func(ctx *gin.Context) {
		body, _ := ctx.GetRawData()
		var 表 lin.J键值表
		表.ZR载入(body)
		方法名 := 表.QW取文本("方法名")
		参数列表 := 表.QL取列表("参数")
		ctx.String(200, 响应_提交方法(方法名, 参数列表))
	})

	// 数据下载入口
	服务端.POST("/linfile", func(ctx *gin.Context) {
		ctx.Writer.Header().Set("Access-Control-Allow-Origin", "*")
		ctx.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
		body, _ := ctx.GetRawData()
		var 表 lin.J键值表
		表.ZR载入(body)
		fmt.Println(string(body))
		方法名 := 表.QW取文本("方法名")
		参数列表 := 表.QL取列表("参数")
		响应文件路径, err := 响应_下载方法(方法名, 参数列表)
		if err != nil {
			ctx.Header("isok", url.QueryEscape(err.Error()))
			ctx.JSON(200, gin.H{
				"msg": err.Error(),
			})
			return
		}
		if 响应文件路径 == "" {
			ctx.Header("isok", url.QueryEscape("接口未获取文件路径"))
			ctx.JSON(200, gin.H{
				"msg": "接口未获取文件路径",
			})
			return
		}

		文件信息, 错误 := os.Stat(响应文件路径)
		fmt.Println(错误, 文件信息)
		if 错误 != nil {
			ctx.Header("isok", url.QueryEscape(错误.Error()))
			ctx.JSON(200, gin.H{
				"msg": 错误.Error(),
			})
			return
		}
		ctx.Header("Content-Description", "File Transfer")
		ctx.Header("Content-Type", "application/octet-stream")
		ctx.Header("fileName", url.QueryEscape(文件信息.Name()))
		ctx.Header("isok", "ok")
		ctx.Header("msg", url.QueryEscape("下载成功_"+文件信息.Name()))
		// 数据, _ := 全_文件.D读入_文件(响应文件路径)
		// ctx.Data(200, "application/octet-stream", 数据)
		ctx.File(响应文件路径)
	})

	// 数据字节集入口
	服务端.POST("/linbytes", func(ctx *gin.Context) {
		ctx.Writer.Header().Set("Access-Control-Allow-Origin", "*")
		ctx.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
		body, _ := ctx.GetRawData()
		var 表 lin.J键值表
		表.ZR载入(body)
		fmt.Println(string(body))
		方法名 := 表.QW取文本("方法名")
		参数列表 := 表.QL取列表("参数")
		字节集数据,err:= 响应_字节集方法(方法名, 参数列表)
		if err != nil {
			ctx.Header("isok", url.QueryEscape(err.Error()))
			ctx.JSON(200, gin.H{
				"msg": err.Error(),
			})
			return
		}
		ctx.Header("isok", "ok")
		ctx.Data(200, "application/octet-stream", 字节集数据)
	})

	//ws服务升级
	服务端.GET("/ws", func(ctx *gin.Context) {
		处理ws链接(ctx)
	})

	服务端.Run(全_文本.C创建文本(":{1}", 全_配置.QW取文本("端口")))

}

func 处理ws链接(ctx *gin.Context) {
	链接, err := ws链接设置.Upgrade(ctx.Writer, ctx.Request, nil)
	if err != nil {
		fmt.Println("ws链接错误")
		return
	}
	var 记录方法名 = ""
	var 记录标识 = ""
	defer func() {
		if 记录方法名 != "" {
			if 记录标识 != "" {
				Ws标识.S删链接(记录方法名, 记录标识, 链接)
			} else {
				Ws广播.S删链接(记录方法名, 链接)
			}
		}
		fmt.Println("ws离开-->", 记录方法名)

	}()
	for {
		_, 数据, err := 链接.ReadMessage()
		if err != nil {
			fmt.Println(err)
			break
		}
		if 记录方法名 == "" {
			var 表 lin.J键值表
			表.ZR载入(数据)
			方法名 := 表.QW取文本("方法名")
			标识 := 表.QW取文本("标识")
			if 方法名 != "" {
				记录方法名 = 方法名
				if 标识 != "" {
					记录标识 = 标识
					Ws标识.Z增加链接(方法名, 标识, 链接)
				} else {
					Ws广播.Z增加链接(方法名, 链接)
				}
			}

		}
	}

}

type X响应 struct {
	方法列表 map[string]func(参数列表 lin.L列表) string
	读写许可 *sync.RWMutex
}

func (类 *X响应) C初始化() {
	类.方法列表 = make(map[string]func(参数列表 lin.L列表) string)
	var 锁 sync.RWMutex
	类.读写许可 = &锁
}

func (类 *X响应) T添加方法(方法名 string, 方法 func(参数列表 lin.L列表) string) {
	类.读写许可.Lock()
	defer 类.读写许可.Unlock()
	类.方法列表[方法名] = 方法
}

func (类 *X响应) X响应(方法名 string, 参数列表 lin.L列表) string {
	类.读写许可.RLock()
	defer 类.读写许可.RUnlock()
	if 方法, ok := 类.方法列表[方法名]; ok {
		return 方法(参数列表)
	}
	return "未绑定方法"

}
